
#include "OkPool.h"
#include "OkPgConnection.h"

using namespace OKPg;

struct Holder {
    int *i;

    static Holder *create(int);

    void destroy() {
        delete this;
    }


protected:
    Holder(int x) : i(new int {x}) {
    };

    ~Holder() {
        delete i;
    };

};

Holder *Holder::create(int x) {
    return new Holder(x);
}

void testDemo() {
    using Pool = OkPool<OkPgConnection>;
    using URL=OkPgUrl;

    //init pool
    URL url("db_core_server", "postgres", "pujie123", "192.168.20.150");
    Pool p(10, [&]() {
        return OkPoolUnique<OkPgConnection>(
                [](OkPgConnection &con) {
                    con.connFree();
                }, OkPgConnection::connNew(url));
    });
    //get con
    Pool::OptPoolItem conOptItem = p.takeItemWithTimeOut(5 * 100);

    //excute
    if (!conOptItem.hasValue()) {
        LOG(INFO) << "can't get connection from pool timeout!";
        return;
    }
    Pool::OkPgPoolTypedefs::PoolItem &conItem = conOptItem.value();

    OkPgConnection &con = conItem.getContent();
    OkPgArgs arg;
    arg.function("fun_room_select_byProjectId")
            .addArg("projectId", "8adc1f909b8749718bd0ed65529da674");

    OkPgResultFuture f = con.executeQuery(arg);
    OkPgResultSet r = f.get();
    if (r.hasError()) {
        LOG(INFO) << "ERROR: " << r.errMsg();
        return;
    }
    r.resultDatatable().foreachDataRow([](DataRow row) {
        LOG(INFO) << "\nroomId:" << row["s_room_id"].toString()
                  << "  roomName:" << row["s_room_name"].toString();
    });

//    f.onError([](const OkPgException &e) {
//        LOG(INFO) << "eeeeeeeeeeee ->" << e.what();
//        return OkPgResultSet(nullptr);
//    }).then([](OkPgResultSet r) {
//        r.resultDatatable().foreachDataRow([](DataRow row) {
//            LOG(INFO) << "\nroomId:" << row["s_room_id"].toString()
//                      << "  roomName:" << row["s_room_name"].toString();
//        });
//    });
    //return con
    std::this_thread::sleep_for(std::chrono::seconds(5));
    p.returnItem(conItem);
}

int main() {

    testDemo();
    return EXIT_SUCCESS;

    using Pool = OkPool<Holder>;
    Pool p(1,
           []() {
               return OkPoolUnique<Holder>(
                       [](Holder &h) { h.destroy(); },
                       Holder::create(1)
               );
           });
    Pool::OptPoolItem optItm = p.takeItem();
    if (optItm.hasValue()) {
        Pool::OkPgPoolTypedefs::PoolItem &v = optItm.value();
        LOG(INFO) << "has value :\t" << *(v.getContent().i);
        p.returnItem(v);
    }

    std::thread th([&]() {
        Pool::OptPoolItem optItmInThread = p.takeItemWithTimeOut(5 * 1000);
        if (!optItmInThread.hasValue()) {
            LOG(INFO) << "time out , no value";
            return;
        }
        Pool::OkPgPoolTypedefs::PoolItem &v2 = optItmInThread.value();
        LOG(INFO) << "in thread , has value :\t" << *(v2.getContent().i);
    });
    th.detach();
    std::this_thread::sleep_for(std::chrono::seconds(15));
    return EXIT_SUCCESS;
}